package cn.demoncat.util.sec;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import cn.demoncat.util.lang.constant.StringConstant;
import cn.demoncat.util.lang.entity.SetStr;

/**
 * MD5 消息摘要（数据唯一签名，不可逆）
 *
 * @author 延晓磊
 *
 * @since 2016年8月11日
 */
public class Md5Util {

	/**
	 * MD5 签名
	 * 
	 * @param data	源数据
	 * @return 数据签名(32位16进制字符串)
	 * 
	 * @author 延晓磊
	 *
	 * @since 2016年8月11日
	 */
	public static String digest(byte[] data) {
		return DigestUtils.md5Hex(data);
	}
	
	/**
	 * MD5 签名
	 * 
	 * @param data	源数据
	 * @return 数据签名(32位16进制字符串)
	 * 
	 * @author 延晓磊
	 *
	 * @since 2016年8月11日
	 */
	public static String digest(String data) {
		return DigestUtils.md5Hex(data);
	}
	
	/**
	 * MD5 签名
	 * 
	 * @param data	源数据
	 * @return 数据签名(32位16进制字符串)
	 * 
	 * @author 延晓磊
	 *
	 * @since 2016年8月11日
	 */
	public static String digest(InputStream data) {
		try {
			return DigestUtils.md5Hex(data);
		} catch (IOException e) {
			throw new RuntimeException("MD5签名失败",e);
		}
	}
	
	
	/**
	 * MD5签名算法
	 * 
	 * @param map  		参数：排除"sign"和"signature"，key的键为"key"
	 * @param key		密钥：如果为空将不拼接，如果非空将拼接在末尾
	 * 
	 * @return 将键按ASCII排序(排除空值) -> 按URL格式拼接 -> MD5签名 -> 转换为大写
	 * 
	 * @author 延晓磊
	 *
	 * @since 2016年8月11日
	 */
	public static String sign(Map<String, String> map, String key) {
		return sign(map, null, null, key);
	}
	
	/**
	 * MD5签名算法
	 * 
	 * @param map  		参数
	 * @param ignores	排除的键：默认["sign","signature"]
	 * @param keyName	密钥的键名：默认"key"
	 * @param key		密钥：如果为空将不拼接，如果非空将拼接在末尾
	 * 
	 * @return 将键按ASCII排序(排除空值) -> 按URL格式拼接 -> MD5签名 -> 转换为大写
	 * 
	 * @author 延晓磊
	 *
	 * @since 2016年8月11日
	 */
	public static String sign(Map<String, String> map, Set<String> ignores, String keyName, String key) {
		// 默认值
		if (ignores == null) {
			ignores = SetStr.getInstance("sign","signature");
		}
		if (StringUtils.isBlank(keyName)) {
			keyName = "key";
		}
		// 组装Map为List
		List<String> list = new ArrayList<>();
		for (Map.Entry<String, String> entry : map.entrySet()) {
			// 将非空Entry放入List
			if (StringUtils.isNotBlank(entry.getValue()) && !ignores.contains(entry.getKey())) {
				// k=v
				list.add(entry.getKey() + StringConstant.EQUAL + entry.getValue());
			}
		}
		// 排序List
		Collections.sort(list);
		// 拼接List元素，以&分隔
		String url = StringUtils.join(list, StringConstant.PARAM_SEPARATOR);
		// 拼接字符串的末尾添加KEY密钥
		if (StringUtils.isNotBlank(key)) {
			url = url + StringConstant.PARAM_SEPARATOR + keyName + StringConstant.EQUAL + key;
		}
		// MD5签名，转换为大写
		return Md5Util.digest(url).toUpperCase();
	}
	
}
